//
//  Validations.swift
//  TuJiaMerchant
//
//  Created by 何海涛 on 16/1/7.
//  Copyright © 2016年 途家. All rights reserved.
//

import Foundation
// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func < <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l < r
  case (nil, _?):
    return true
  default:
    return false
  }
}

// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func <= <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l <= r
  default:
    return !(rhs < lhs)
  }
}

// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func >= <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l >= r
  default:
    return !(lhs < rhs)
  }
}

// FIXME: comparison operators with optionals were removed from the Swift Standard Libary.
// Consider refactoring the code to use the non-optional operators.
fileprivate func > <T : Comparable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l > r
  default:
    return rhs < lhs
  }
}


/* Common validation rules */

/// Required
public class RequiredValidationRule : ValidationRule {
    
    public enum EnumRequiredValidationScene : String {
        case Normal = "%@不能为空"
        case Enter = "请输入%@"
        case Optional = "请选择%@"
    }
    
    public var scene : EnumRequiredValidationScene!
    public var whiteSpaceEqualEmpty = true
    
    public init(memberName name: String, displayName display: String? = nil, scene : EnumRequiredValidationScene = .Normal, whiteSpaceEqualEmpty: Bool = true) {
        self.scene = scene
        self.whiteSpaceEqualEmpty = whiteSpaceEqualEmpty
        super.init(memberName: name, displayName: display)
    }
    
    override public func valid(_ val: AnyObject?, allVals: [String : AnyObject]) -> Bool {
        if val == nil {
            return false
        } else if let strVal = val as? String {
            return !strVal.isEmpty && !strVal.trim().isEmpty
        }
        return true
    }
    
    override public func errorFormat(_ val: AnyObject?, allVals: [String : AnyObject]) -> String {
        return String(format: NSLocalizedString(self.scene.rawValue, comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"),(self.displayName ?? self.memberName))
    }
    
}

/// Compare
public class CompareValidationRule : ValidationRule {
    var compareMemberName : String
    var compareDisplayName : String?
    
    public init(memberName name : String, compareMemberName compare : String, displayName display : String? = nil, compareDisplayName compareDisplay : String? = nil) {
        self.compareMemberName = compare
        self.compareDisplayName = compareDisplay
        super.init(memberName: name, displayName: display)
    }
    
    override public func valid(_ val: AnyObject?, allVals: [String : AnyObject]) -> Bool {
        let compareVal = allVals[self.compareMemberName]
        if val == nil && compareVal != nil {
            return false
        } else if val != nil && compareVal != nil {
            return val!.isEqual(compareVal)
        }
        return true
    }
    
    override public func errorFormat(_ val: AnyObject?, allVals: [String : AnyObject]) -> String {
        return String(format: NSLocalizedString("%1$@与%2$@不相等", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"),(self.displayName ?? self.memberName),(self.compareDisplayName ?? self.compareMemberName))
    }
}

/// String Length
public class StringLengthValidationRule : ValidationRule {
    var minLength : Int
    var maxLength : Int
    
    public init(memberName name: String, displayName display: String? = nil, minLength min : Int = 0, maxLength max : Int) {
        self.minLength = min
        self.maxLength = max
        super.init(memberName: name, displayName: display)
    }
    
    override public func valid(_ val: AnyObject?, allVals: [String : AnyObject]) -> Bool {
        if let v = val {
            let str = String(describing: v)
            if minLength > 0 && maxLength > 0{
                return str.length <= maxLength && str.length >= minLength
            } else if maxLength > 0 {
                return str.length <= maxLength
            } else {
                return str.length >= minLength
            }
        }
        return true
    }
    
    override public func errorFormat(_ val: AnyObject?, allVals: [String : AnyObject]) -> String {
        let name = self.displayName ?? self.memberName
        var suffix = NSLocalizedString("长度错误", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift")
        if (minLength > 0 && maxLength > 0){
            suffix = String(format: NSLocalizedString("长度必须在%1$@和%2$@个字符之间", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"),minLength.description,maxLength.description)
        } else if maxLength > 0{
            suffix = String(format: NSLocalizedString("长度不能超过%@个字符", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), maxLength.description)
        } else if minLength > 0 {
            suffix = String(format: NSLocalizedString("长度不能少于%@个字符", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), minLength.description)
        }
        return name + suffix
    }
}
// @"^[0-9]{1,8}([.][0-9]{1,2})?$";
public class RegexValidationRule : ValidationRule {
    public var pattern : String
    
    public init(memberName name: String, displayName display: String? = nil, pattern : String, errorMessage : String) {
        self.pattern = pattern
        super.init(memberName: name, displayName: display)
        self.errorMessage = errorMessage
    }
    
    override public func valid(_ val: AnyObject?, allVals: [String : AnyObject]) -> Bool {
        if let v = val {
            if let str = v as? String, str.isEmpty { return true }
            return Regex(self.pattern).test(String(describing: v))
        }
        return true
    }
    
    override public func errorFormat(_ val: AnyObject?, allVals: [String : AnyObject]) -> String {
        return self.errorMessage ?? ""
    }
}

public protocol CustomStringConvertibleForValidation {
    var validationDescription: String { get }
}

extension Int : CustomStringConvertibleForValidation {
    public var validationDescription: String { return self.description }
}

extension Double : CustomStringConvertibleForValidation {
    public var validationDescription: String { return self == Double(Int(self)) ? Int(self).description : self.description }
}

/// Range
public class RangeValidationRule<T: Comparable & CustomStringConvertibleForValidation>: ValidationRule {
    public typealias RangeValue = (val: T, criticle: Bool)
    public var min : RangeValue?
    public var max : RangeValue?
    public var converter: ((_:AnyObject)->T?) = { (v) in v as? T }
    public var ignores: [T]
    
    public init(memberName name: String, displayName display: String?, min: RangeValue, errorMessage : String? = nil, ignores: [T] = [], converter: ((_:AnyObject)->T?)? = nil) {
        self.ignores = ignores
        super.init(memberName: name, displayName: display)
        self.min = min
        if converter != nil { self.converter = converter! }
        self.errorMessage = errorMessage
    }
    
    public init(memberName name: String, displayName display: String?, max: RangeValue, errorMessage : String? = nil, ignores: [T] = [], converter: ((_:AnyObject)->T?)? = nil) {
        self.ignores = ignores
        super.init(memberName: name, displayName: display)
        self.max = max
        if converter != nil { self.converter = converter! }
        self.errorMessage = errorMessage
    }
    
    public init(memberName name: String, displayName display: String?, min: RangeValue, max: RangeValue, errorMessage : String? = nil, ignores: [T] = [], converter: ((_:AnyObject)->T?)? = nil) {
        self.ignores = ignores
        super.init(memberName: name, displayName: display)
        self.min = min
        self.max = max
        if converter != nil { self.converter = converter! }
        self.errorMessage = errorMessage
    }
    
    public convenience init(memberName name: String, displayName display: String?, min: T, errorMessage : String? = nil, ignores: [T] = [], converter: ((_:AnyObject)->T?)? = nil) {
        self.init(memberName: name, displayName: display, min: (min, true), errorMessage: errorMessage, ignores: ignores, converter: converter)
    }
    
    public convenience init(memberName name: String, displayName display: String?, max: T, errorMessage : String? = nil, ignores: [T] = [], converter: ((_:AnyObject)->T?)? = nil) {
        self.init(memberName: name, displayName: display, max: (max, true), errorMessage: errorMessage, ignores: ignores, converter: converter)
    }
    
    public convenience init(memberName name: String, displayName display: String?, min: T, max: T, errorMessage : String? = nil, ignores: [T] = [], converter: ((_:AnyObject)->T?)? = nil) {
        self.init(memberName: name, displayName: display, min: (min, true), max: (max, true), errorMessage: errorMessage, ignores: ignores, converter: converter)
    }
    
    override public func valid(_ val: AnyObject?, allVals: [String : AnyObject]) -> Bool {
        if let v = val {
            if let str = v as? String, str.isEmpty { return true }
            let current = converter(v)
            if current == nil || self.ignores.contains(current!) { return true }
            let minResult = min == nil || (min!.criticle ? min!.val <= current : min!.val < current)
            let maxResult = max == nil || (max!.criticle ? max!.val >= current : max!.val > current)
            return minResult && maxResult
        }
        return true
    }
    
    override public func errorFormat(_ val: AnyObject?, allVals: [String : AnyObject]) -> String {
        let name = self.displayName ?? self.memberName
        if min != nil && max != nil && min!.criticle && max!.criticle {
            return name + String(format: NSLocalizedString("必须在%1$@与%2$@之间", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), min!.val.validationDescription, max!.val.validationDescription)
        } else {
            var prefixMin : String? = nil
            var prefixMax : String? = nil
            if min != nil {
                prefixMin = min!.criticle ?
                    String(format: NSLocalizedString("不能小于%@", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), min!.val.validationDescription):
                    String(format: NSLocalizedString("必须大于%@", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), min!.val.validationDescription)
            }
            if max != nil {
                prefixMax = max!.criticle ?
                    String(format: NSLocalizedString("不能大于%@", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), max!.val.validationDescription):
                    String(format: NSLocalizedString("必须小于%@", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), max!.val.validationDescription)
            }
            let combineStr = NSLocalizedString("且", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift")
            var prefixArray = [String]()
            if prefixMin != nil { prefixArray.append(prefixMin!) }
            if prefixMax != nil { prefixArray.append(prefixMax!) }
            let prefix = prefixArray.joined(separator: combineStr)
            return name + prefix
        }
    }
}

/// Number
public class NumberValidationRule : ValidationRule {
    
    var signed : Bool = false
    var decimalPlace: Int = 2
    var forceInterger = true
    fileprivate var isOutOfDecimal = false //临时变量区分forceInterger＝true时.00是否超出小数点位数，以给出更精确的提示
    
    public init(memberName name: String, displayName display: String?, decimalPlace: Int, signed : Bool = false, forceInterger: Bool = true) {
        // 目前主要应用输入货币的场景，基本上都是输入整数的。
        self.forceInterger = forceInterger
        self.decimalPlace = decimalPlace
        super.init(memberName: name, displayName: display)
    }
    
    override public func valid(_ val: AnyObject?, allVals: [String : AnyObject]) -> Bool {
        if let v = val {
            if let str = v as? String, str.isEmpty { return true }
            var pattern = "\\d{1,}"
            if signed {
                pattern = "[-]{0,1}" + pattern
            }
            if decimalPlace > 0 {
                let digitAfterDecimal = forceInterger ? "0" : "\\d"
                pattern = pattern + "\\.?" + digitAfterDecimal + "{0," + decimalPlace.description + "}"
            }
            pattern = "^" + pattern + "$"
            let strForTest = String(describing: v)
            isOutOfDecimal = Regex("^-?\\d+.\\d{\(decimalPlace+1),}$").test(strForTest)
            return Regex(pattern).test(strForTest)
        }
        return true
    }
    
    override public func errorFormat(_ val: AnyObject?, allVals: [String : AnyObject]) -> String {
        let name = self.displayName ?? self.memberName
        if self.decimalPlace == 0 || (self.forceInterger && !isOutOfDecimal) {
            return name + String(format: NSLocalizedString("必须为整数", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"))
        } else {
            return name + String(format: NSLocalizedString("仅支持小数点后%d位", comment: "./PMS/Classes/Extension/Validation/ModelValidations.swift"), self.decimalPlace)
        }
    }
}
